#!/usr/bin/python
#coding: utf-8

"""
也可以对多进程不适用共享内存，在数据库中增加一个字段，判断该URL是否已经爬取过，没有爬取过，正在爬取。
"""

import sys
sys.path.append("..")

import time
import lxml.html
import random
import urlparse
import threading as td
import multiprocessing as mp
from Downloader.UrlDownloader import DownloaderPageHtml
from Config.Config import USER_AGENTS, BaseUrl, TimeSleep
from EveryPageAnalysis import EveryPage
# from EveryPageAnalysis.EveryPageAnalysis import EveryPage
from Logging.UrlLogging import log_Main

class SoftPageAnalysis(object):
    def __init__(self, pageUrl):
        self.pageUrl = pageUrl
        self.everypage = EveryPage()
        self.nums = len(pageUrl)

    def mp_crawler(self, ):
        u"启动多进程"
        cpuCount = mp.cpu_count()

        # 创建共享内存
        m = mp.Manager()
        value = m.list(self.pageUrl)
        # log_Main(u"创建共享内存", "info")

        print u"链接总个数为%d" % self.nums

        lock = mp.Lock()
        processes = []
        # log_Main(u"创建进程锁,保证进程的数量始终为4", "info")
        while len(processes) < cpuCount and value:
            for process in processes:
                if not process.is_alive():
                    processes.remove(process)
            for i in range(0, cpuCount - len(processes)):
                if len(value) == 0:
                    break
                p = mp.Process(target= self.crawler, name= "multiprocessing-%d" % (len(processes) + 1), args= (lock, value))
                # p.daemon = False # 如果说不是守护进程的话，则在主进程结束以后子进程并不会结束。在本例中要保证所有的进程都自动结束
                # p.daemon = True # 守护进程就是不阻挡主程序退出，自己干自己的
                p.start()
                p.join() # 等待所有进程完成
                processes.append(p)

            while len(processes) == cpuCount:
                for process in processes:
                    if not process.is_alive():
                        processes.remove(process)

    def crawler(self, lock, value):
        # 输出当前线程的名称，同时也可以判断开启的线程的数量
        print mp.current_process().name
        try:
            url = value.pop()
        except Exception as e:
            # 由于多进程同时运行，同时把进程锁放在了解析的页面，所以此时可能会存在抢占CPU的运行，可能之前的子进程刚把共享内存中的
            # list给清空，又运行到这里，所以此时要终止进程的执行
            return
        print u"正在爬取第%d页的应用链接" % (self.nums - len(value))
        url = urlparse.urljoin(BaseUrl, url)
        # print url
        # log_Main(u"当前要爬取的链接为：%s" % url, "info")
        D = DownloaderPageHtml(url, USER_AGENTS[random.randint(0, len(USER_AGENTS) - 1)]).Downloader(3)
        # 爬取过程中发现了一个坑爹的错误，有的网页返回的代码长度是23423，但是并没有获取到信息，所以再此处进行一次循环爬取
        # 观察发现，此时是ip被禁了，还有一种情况是这个应用被删除了（此时就需要设置递归爬取网页的深度），
        # 所以没办法，使用代理IP的时候到了
        # 但是在使用代理IP的时候发现代理IP爬取非常慢，所以，没办法，只能在每一次爬取完之后休眠1s，模拟人正常访问网页
        # 如果网页是23424的话，则直接在此循环就可以，因为这个网页禁止访问的时间特别短
        num = 5
        while len(D) == 23424 and num > 0:
            # log_Main(u"ip被封禁，没办法，循环等待吧", "info")
            time.sleep(TimeSleep)
            num -= 1
            D = DownloaderPageHtml(url, USER_AGENTS[random.randint(0, len(USER_AGENTS) - 1)]).Downloader(3)

        if num > 0:
            # 下载好网页以后，在网页解析的时候加锁，防止信息错乱,不在爬取网页的时候加锁，那样多进程并不能起到优化时间的作用
            lock.acquire()
            print u"当前页面爬取成功，即将进行解析！！！"
            self.everypage.getAllUrl(D)
            lock.release()